
#ifndef PrimaryThreadLoader_h
#define PrimaryThreadLoader_h

#include <Typedef.h>
#include <Defines.h>
#include <CSharpPropertyMethods.h>

#include <System/Object.h>
#include <System/DateTime.h>
#include <System/Collections/Generic/List.h>
#include <System/Activator.h>

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
			/// <summary>
			/// Interface used to add an object to be loaded on the primary thread
			/// </summary>
			interface IPrimaryThreadLoaded
			{
				public: bool Load();
			};

			/// <summary>
			/// Static class that is called before every draw to load resources that need to finish loading on the primary thread
			/// </summary>
			/*internal static*/ class PrimaryThreadLoader sealed : public Riccsson::System::object
			{

				private: static /*readonly*/ GC_PTR<Riccsson::System::object> ListLockObject;
				private: static /*readonly*/ GC_PTR<Riccsson::System::Collections::Generic::List<GC_PTR<IPrimaryThreadLoaded>>> NeedToLoad; 
				private: static /*readonly*/ GC_PTR<Riccsson::System::Collections::Generic::List<GC_PTR<IPrimaryThreadLoaded>>> RemoveList;
				private: static Riccsson::System::DateTime _lastUpdate;

				REGISTER_ABSTRACT_CLASS(PrimaryThreadLoader)

				public: static void AddToList(IPrimaryThreadLoaded* primaryThreadLoaded)
				{
					lock (ListLockObject)
					{
						NeedToLoad->Add(primaryThreadLoaded);
					}
				}

				public: static void RemoveFromList(IPrimaryThreadLoaded* primaryThreadLoaded)
				{
					lock (ListLockObject)
					{
						NeedToLoad->Remove(primaryThreadLoaded);
					}
				}

				public: static void RemoveFromList(Riccsson::System::Collections::Generic::List<GC_PTR<IPrimaryThreadLoaded>>* primaryThreadLoadeds)
				{
					lock (ListLockObject)
					{
						foreach2 (var, primaryThreadLoaded, primaryThreadLoadeds)
						{
							NeedToLoad->Remove(*primaryThreadLoaded);
						}
					}
				}

				public: static void Clear()
				{
					lock(ListLockObject)
					{
						NeedToLoad->Clear();
					}
				}

				/// <summary>
				/// Loops through list and loads the item.  If successful, it is removed from the list.
				/// </summary>
				public: static void DoLoads()
				{
					if((Riccsson::System::DateTime::Now - _lastUpdate).Milliseconds < 250) return;

					_lastUpdate = Riccsson::System::DateTime::Now;
					lock (ListLockObject)
					{
						for (int i = 0; i < NeedToLoad->Count; i++)
						{
							IPrimaryThreadLoaded* primaryThreadLoaded = (**NeedToLoad)[i];
							if (primaryThreadLoaded->Load())
							{
								RemoveList->Add(primaryThreadLoaded);
							}
						}

						for (int i = 0; i < RemoveList->Count; i++)
						{
							IPrimaryThreadLoaded* primaryThreadLoaded = (**RemoveList)[i];
							NeedToLoad->Remove(primaryThreadLoaded);
						}

						RemoveList->Clear();
					}
				}
			};
		}
	}
}

#endif